package com.sunzr0119.conventioncentertemplatebackend.service.impl;

import com.mongodb.client.gridfs.model.GridFSFile;
import com.sunzr0119.conventioncentertemplatebackend.dao.FileDAO;
import com.sunzr0119.conventioncentertemplatebackend.dao.UserDAO;
import com.sunzr0119.conventioncentertemplatebackend.dto.SubmittedUser;
import com.sunzr0119.conventioncentertemplatebackend.dto.UploadFileDTO;
import com.sunzr0119.conventioncentertemplatebackend.entity.File;
import com.sunzr0119.conventioncentertemplatebackend.entity.User;
import com.sunzr0119.conventioncentertemplatebackend.service.FileService;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import lombok.RequiredArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {
    private final GridFSBucket gridFSBucket;
    private final FileDAO fileRepository;
    private final UserDAO userRepository;

    private String buildContentDisposition(String fileName) {
        try {
            // 使用 UTF-8 编码文件名，以便浏览器能够正确解析中文字符
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            return "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName;
        } catch (UnsupportedEncodingException e) {
            // 如果编码失败，使用原始文件名
            return "attachment; filename=\"" + fileName + "\"";
        }
    }

    @Override
    public UploadFileDTO uploadFile(MultipartFile file, String uploaderId) {
        try {
            // 使用 GridFS 存储文件
            GridFSUploadOptions options = new GridFSUploadOptions()
                    .metadata(new org.bson.Document("contentType", file.getContentType()));

            ObjectId gridFsId = gridFSBucket.uploadFromStream(Objects.requireNonNull(file.getOriginalFilename()), file.getInputStream(), options);

            // 保存文件信息到 MongoDB
            File fileEntity = new File();
            fileEntity.setUploaderId(uploaderId);
            fileEntity.setFileName(file.getOriginalFilename());
            fileEntity.setContentType(file.getContentType());
            fileEntity.setSize(file.getSize());
            fileEntity.setGridFsId(gridFsId.toHexString());

            fileRepository.save(fileEntity);

            // 构建返回 DTO
            UploadFileDTO responseDTO = new UploadFileDTO();
            responseDTO.setId(fileEntity.getId());
            responseDTO.setFileName(fileEntity.getFileName());
            responseDTO.setSize(fileEntity.getSize());
            responseDTO.setContentType(fileEntity.getContentType());
            responseDTO.setDownloadUrl("/file-api/" + fileEntity.getId());  // 提供下载 URL

            return responseDTO;
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }

    }

    @Override
    public ResponseEntity<Resource> getFileResource(String fileId, boolean download) {
        // 获取文件信息
        File fileEntity = fileRepository.findById(fileId).orElse(null);
        if (fileEntity == null) {
            return ResponseEntity.notFound().build();
        }

        // 获取 GridFS 文件
        ObjectId gridFsId = new ObjectId(fileEntity.getGridFsId());
        GridFSFile gridFSFile = gridFSBucket.find(new org.bson.Document("_id", gridFsId)).first();
        if (gridFSFile == null) {
            return ResponseEntity.notFound().build();
        }

        InputStream inputStream = gridFSBucket.openDownloadStream(gridFsId);
        Resource resource = new InputStreamResource(inputStream);

        // 下载时添加附件头
        HttpHeaders headers = new HttpHeaders();
        if (download) {
            headers.add(HttpHeaders.CONTENT_DISPOSITION, buildContentDisposition(fileEntity.getFileName()));
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        }

        // 预览时直接返回资源
        MediaType mediaType = MediaType.parseMediaType(fileEntity.getContentType());

        return ResponseEntity.ok()
                .contentType(mediaType)
                .body(resource);
    }

    @Override
    public ResponseEntity<List<File>> getUsersFileList(String userId) {
        List<File> listBuf = fileRepository.findByUploaderId(userId);
        if (listBuf == null) {
            return ResponseEntity.notFound().build();
        }else {
            return ResponseEntity.ok(listBuf);
        }
    }

    @Override
    public void deleteFile(String fileId) {
        fileRepository.deleteById(fileId);
    }

    @Override
    public ResponseEntity<List<SubmittedUser>> getSubmittedUsers() {
        // 获取所有文件
        List<File> allFiles = fileRepository.findAll();

        // 使用 Map 存储 <uploadId, List<FileEntity>>
        Map<String, List<File>> fileMap = allFiles.stream()
                .collect(Collectors.groupingBy(File::getUploaderId));

        // 构造返回数据
        List<SubmittedUser> submittedUsers = fileMap.entrySet().stream()
                .map(entry -> {
                    String uploadId = entry.getKey();
                    List<File> files = entry.getValue();

                    // 通过 uploadId 查询用户名
                    User user = userRepository.findById(uploadId).orElse(null);
                    String username = (user != null) ? user.getUsername() : "未知用户";

                    return new SubmittedUser(username, files);
                })
                .collect(Collectors.toList());

        return ResponseEntity.ok(submittedUsers);
    }
}